package kit.docker.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.docker.core.mvc.Remark;
import com.jfinal.kit.StrKit;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author ldl
 * @Create 2020/06/25 025 10:45
 */
@Remark("表格读取通用监听器")
public class BaseReadListener<T> extends AnalysisEventListener<T> {

    protected ExcelReadResult<T> readResult;//读取的结果
    protected List<T> successList = new ArrayList<>();//读取成功的结果行
    protected List<T> failList = new ArrayList<>();//读取失败的结果行
    protected LinkedList<String> headList;//待校验的表格头
    protected Map<Integer, String> headMap = new HashMap<>();//读取到的表格头
    protected T data;//每行的数据

    //每一条数据解析都会来调用
    @Override
    public void invoke(T data, AnalysisContext context) {
        this.data = data;
        successList.add(data);
    }

    //所有数据解析完成了 都会来调用
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        readResult = new ExcelReadResult<>();
        readResult.setSuccessList(successList);
        readResult.setFailList(failList);
    }

    //headMap为读取到的第一行的表格头，如：{0:"姓名",1:"年龄",2:"生日"}
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
        if (StrKit.notNull(headList) && !headList.isEmpty()) {
            if (headMap.size() != headList.size()) {
                throw new RuntimeException("表格头不符合规范");
            }
            for (Integer integer : headMap.keySet()) {
                if (!headMap.get(integer).equals(headList.get(integer))) {
                    throw new RuntimeException("表格头不符合规范");
                }
            }
        }
    }

    //在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            System.out.println("第" + excelDataConvertException.getRowIndex() + "行，"
                    + "第" + excelDataConvertException.getColumnIndex() + "列解析异常：" + exception.getMessage());
            String errorMsg = "单元格"
                    + excelDataConvertException.getColumnIndex() + excelDataConvertException.getRowIndex()//单元格坐标"A1"
                    + "解析异常：" + exception.getMessage();
            //设置错误信息
            Class<?> aClass = data.getClass();
            try {
                Field errMsg = aClass.getDeclaredField("error_msg");
                errMsg.setAccessible(true);
                Object errMsgObj = errMsg.get(data);
                if (StrKit.notNull(errMsgObj)) {
                    errorMsg = errMsgObj.toString() + "；" + errorMsg;
                }
                errMsg.set(data, errorMsg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {//也可以对其他异常单独处理
            throw new RuntimeException(exception.getMessage());
        }

//        if (exception instanceof RuntimeException) {
//            throw new RuntimeException(exception.getMessage());
//        }

    }

    public BaseReadListener() {
    }

    public BaseReadListener(LinkedList<String> headList) {
        this.headList = headList;
    }

    public ExcelReadResult<T> getReadResult() {
        return readResult;
    }

    public Map<Integer, String> getHeadMap() {
        return headMap;
    }
}
